package variabilitysmelldetection.analyses;

import java.util.ArrayList;
import java.util.List;

import variabilitysmelldetection.measurement.measures.Measure;
import variabilitysmelldetection.measurement.measures.component.CouplingBetweenObjects;
import variabilitysmelldetection.measurement.measures.component.LinesOfCode;
import variabilitysmelldetection.measurement.measures.component.NumberOfConstantRefinements;
import variabilitysmelldetection.measurement.measures.component.WeightedMethodsPerClass;
import variabilitysmelldetection.measurement.models.ComponentItem;
import variabilitysmelldetection.measurement.models.Project;
import variabilitysmelldetection.plugin.Activator;
import variabilitysmelldetection.plugin.preferences.PreferenceConstants;


public class GodClass {
	private double LOC_THRESHOLD;
	private double NCR_THRESHOLD;
	private double CYCLO_THRESHOLD;
	private double CBO_THRESHOLD;
	private String strategy;

	public GodClass(){
		LOC_THRESHOLD   = Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GODCLASS_LOC_THRESHOLD);//58.53; // high
		NCR_THRESHOLD   = Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GODCLASS_NCR_THRESHOLD);//4.41;  // high
		CYCLO_THRESHOLD = Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GODCLASS_CYCLO_THRESHOLD);//0.24;  // high
		CBO_THRESHOLD   = Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GODCLASS_CBO_THRESHOLD);//2.97;  // low
		strategy = "(NCR > "+NCR_THRESHOLD+") OR "
                + "((LoC > "+LOC_THRESHOLD+") AND "
                + "(CBO > "+CBO_THRESHOLD+") AND "
                + "((WMC/LoC) > "+CYCLO_THRESHOLD+"))";
	}
	
	public String getStrategy(){
		return strategy;
	}
	
	public List<ComponentItem> getGodClasses(Project project){
		List<ComponentItem> godClasses = new ArrayList<ComponentItem>();
		
		for (ComponentItem classe : project.getClassItems()) {
			if (hasGodClass(classe)){
				godClasses.add(classe);
			}
		}
		return godClasses;
	}
	
	public boolean hasGodClass(ComponentItem component){
		double numOverrides = calculateRefinements(component);
		double loc          = calculateLoC(component);
		double cyclo        = calculateCyclo(component);
		double cbo          = calculateCBO(component);
		return ((numOverrides > NCR_THRESHOLD) ||
				((loc > LOC_THRESHOLD) &&
				(cyclo > CYCLO_THRESHOLD) &&
				(cbo > CBO_THRESHOLD)));
	}
	
	private double calculateRefinements(ComponentItem classe){
		double value = 0d;
		Measure nrt = classe.getMeasure(NumberOfConstantRefinements.class);
		if (nrt != null) {
			value = nrt.getValue();
		}
		
		return value;
	}
	
	private double calculateLoC(ComponentItem classe){
		double value = 0d;
		Measure loC = classe.getMeasure(LinesOfCode.class);
		if (loC != null) {
			value = loC.getValue();
		}
		
		return value;
	}
	
	private double calculateCyclo(ComponentItem classe){
		double value = 0d;
		Measure loc  = classe.getMeasure(LinesOfCode.class);
		Measure cyclo = classe.getMeasure(WeightedMethodsPerClass.class);
		if (loc != null && cyclo != null) {
			value = cyclo.getValue() / loc.getValue();
		}
		
		return value;
	}
	
	private double calculateCBO(ComponentItem classe){
		double value = 0d;
		Measure cbo  = classe.getMeasure(CouplingBetweenObjects.class);
		if (cbo != null) {
			value = cbo.getValue();
		}
		
		return value;
	}
}
